using Spire.Pdf;
using Spire.Pdf.Bookmarks;
using Spire.Pdf.General;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Documents;
using WPFPractice.Annotations;
using Color = System.Drawing.Color;
using MessageBox = System.Windows.Forms.MessageBox;

namespace WPFPractice
{
    /// <summary>
    /// (见 https://gitee.com/dlgcy/SpirePdfTool)
    /// </summary>
    public partial class WinSpirePdf : Window, INotifyPropertyChanged
    {
        #region BindableBase

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
        {
            if (Equals(storage, value)) return false;

            storage = value;
            OnPropertyChanged(propertyName);
            return true;
        }

        #endregion

        private string _FileName = "AddBookmark.pdf";
        private PdfDocument _Pdf = new PdfDocument();

        private List<BookmarkItem> _ListBookmarks;
        public List<BookmarkItem> ListBookmarks
        {
            get => _ListBookmarks;
            set => SetProperty(ref _ListBookmarks, value);
        }

        //public ObservableCollection<BookmarkItem> ListBookmarks { get; set; } = new ObservableCollection<BookmarkItem>();

        private bool _CanAdd;
        public bool CanAdd
        {
            get => _CanAdd;
            set => SetProperty(ref _CanAdd, value);
        }

        private bool _CanModify;
        public bool CanModify
        {
            get => _CanModify;
            set => SetProperty(ref _CanModify, value);
        }

        public WinSpirePdf()
        {
            InitializeComponent();
            DataContext = this;
        }

        #region 测试区

        //测试：《C# 添加、修改和删除 PDF 书签》
        //https://www.cnblogs.com/Yesi/p/7251214.html

        private void BtnAddBookmarks_Click(object sender, EventArgs e)
        {
            //新建PDF文档
            PdfDocument pdf = new PdfDocument();

            //添加页面
            PdfPageBase page = pdf.Pages.Add();

            //添加书签
            PdfBookmark bookmark = pdf.Bookmarks.Add("第一页");

            //设置书签所指向的页面和位置，（0,0）表示页面的开始位置
            //bookmark.Destination = new PdfDestination(page)
            //{
            //    Location = new PointF(0, 0)
            //};

            bookmark.Destination = new PdfDestination(0, new PointF(0, 0), 0);

            //设置书签的文本格式和颜色
            bookmark.DisplayStyle = PdfTextStyle.Bold;
            bookmark.Color = Color.Black;

            //再添加一页，供其它功能测试使用;
            pdf.Pages.Add();

            //保存文档
            pdf.SaveToFile(_FileName);

            MessageBox.Show($"已保存文件{_FileName}");
        }

        private void BtnAddSubBookmarks_Click(object sender, EventArgs e)
        {
            //新建PDF文档
            PdfDocument pdf = new PdfDocument();

            //添加页面
            PdfPageBase page = pdf.Pages.Add();

            //添加书签
            PdfBookmark bookmark = pdf.Bookmarks.Add("第一章 热传导");

            //设置书签指向的页面和位置
            bookmark.Destination = new PdfDestination(page) { Location = new PointF(0, 0) };

            //设置书签的文本格式和颜色
            bookmark.DisplayStyle = PdfTextStyle.Bold;
            bookmark.Color = Color.SeaGreen;

            //添加子书签
            PdfBookmark childBookmark = bookmark.Insert(0, "1.1 热传导基本知识");

            //设置子书签指向的页面和位置
            childBookmark.Destination = new PdfDestination(page) { Location = new PointF(400, 300) };

            //设置子书签的文本格式和颜色
            childBookmark.DisplayStyle = PdfTextStyle.Regular;
            childBookmark.Color = Color.Black;

            //保存文档
            string fileName = "ChildBookmark.pdf";
            pdf.SaveToFile(fileName);

            MessageBox.Show($"已保存文件{fileName}");
        }

        private void BtnAddToFile_Click(object sender, EventArgs e)
        {
            //加载文档
            PdfDocument pdf = new PdfDocument();
            pdf.LoadFromFile(_FileName);

            for (int i = 0; i < pdf.Pages.Count; i++)
            {
                //添加书签
                PdfBookmark bookmark = pdf.Bookmarks.Add($"第{i + 1}章");

                //设置书签指向的页面和位置
                bookmark.Destination = new PdfDestination(pdf.Pages[i]) { Location = new PointF(0, 0) };

                //设置书签的文本格式和颜色
                bookmark.DisplayStyle = PdfTextStyle.Bold;
                bookmark.Color = Color.Black;
            }

            //保存文档
            pdf.SaveToFile(_FileName);

            MessageBox.Show($"已保存文件{_FileName}");
        }

        private void BtnModify_Click(object sender, EventArgs e)
        {
            //加载文档
            PdfDocument pdf = new PdfDocument();
            pdf.LoadFromFile(_FileName);

            //获取书签列表
            PdfBookmarkCollection bookmarks = pdf.Bookmarks;

            //获取第一个书签
            PdfBookmark bookmark = bookmarks[0];

            //修改书签指向的页面
            bookmark.Destination = new PdfDestination(pdf.Pages[1]);

            //修改书签的文本格式和颜色
            bookmark.DisplayStyle = PdfTextStyle.Bold;
            bookmark.Color = Color.Green;

            //修改书签的title
            bookmark.Title = "修改";

            //保存文档
            string fileName = "ModifyBookmark.pdf";
            pdf.SaveToFile(fileName);

            MessageBox.Show($"已保存文件{fileName}");
        }

        private void BtnInsert_Click(object sender, EventArgs e)
        {
            //加载文档
            PdfDocument pdf = new PdfDocument();
            pdf.LoadFromFile(_FileName);

            //插入新书签到指定位置（此处插入的是第三个书签的位置）
            PdfBookmark bookmark = pdf.Bookmarks.Insert(2, "新增第三章");

            //设置书签所指向的页面和位置
            bookmark.Destination = new PdfDestination(pdf.Pages[1]);
            bookmark.Destination.Location = new PointF(0, 300);

            //保存文档
            string fileName = "InsertBookmark.pdf";
            pdf.SaveToFile(fileName);

            MessageBox.Show($"已保存文件{fileName}");
        }

        private void BtnDelete_Click(object sender, EventArgs e)
        {
            //加载文档
            PdfDocument pdf = new PdfDocument();
            pdf.LoadFromFile(_FileName);

            //获取书签列表
            PdfBookmarkCollection bookmarks = pdf.Bookmarks;

            //删除第一个书签
            bookmarks.RemoveAt(0);

            //保存文档
            string fileName = "DeleteBookmark.pdf";
            pdf.SaveToFile(fileName);

            MessageBox.Show($"已保存文件{fileName}");
        }

        /// <summary>
        /// 破解方法：移除第一页版权信息
        /// https://blog.csdn.net/weixin_38211198/article/details/90115310
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnCrack_Click(object sender, EventArgs e)
        {
            //新建PDF文档
            PdfDocument pdf = new PdfDocument();

            //添加页面
            pdf.Pages.Add();
            pdf.Pages.Add();
            pdf.Pages.RemoveAt(0);

            //保存文档
            string fileName = "Crack.pdf";
            pdf.SaveToFile(fileName);

            MessageBox.Show($"已保存文件{fileName}");
        }

        #endregion

        private void BtnChooseFile_Click(object sender, EventArgs e)
        {
            Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog { Filter = "PDF文件|*.pdf" };
            if (dialog.ShowDialog() == true)
            {
                TbPath.Text = _FileName = dialog.FileName;
                //MessageBox.Show($"已选择文件{_FileName}");

                if (LoadBookmarks())
                {
                    //MessageBox.Show("载入书签成功");
                }
                else
                {
                    MessageBox.Show("载入书签失败");
                }
            }
        }

        private bool LoadBookmarks()
        {
            bool result = false;

            try
            {
                //PdfDocument pdf = new PdfDocument();
                _Pdf.LoadFromFile(_FileName);

                //获取书签列表
                PdfBookmarkCollection bookmarks = _Pdf.Bookmarks;

                List<BookmarkItem> list = new List<BookmarkItem>();
                for (int i = 0; i < bookmarks.Count; i++)
                {
                    try
                    {
                        var bookmark = bookmarks[i];
                        var page = bookmark.Destination.Page;
                        int num = _Pdf.Pages.IndexOf(page) + 1;

                        list.Add(new BookmarkItem()
                        {
                            Index = i,
                            Page = num,
                            Title = bookmark.Title
                        });
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"第{i + 1}个书签载入失败：{ex}");
                    }
                }

                ListBookmarks = list;
                //TvBookmarks.ItemsSource = ListBookmarks;
                //TvBookmarks.SelectedValuePath = "Index";
                //TvBookmarks.DisplayMemberPath = "Title";

                CanAdd = true;
                result = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            return result;
        }

        private void TvBookmarks_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            var bookmarkItem = e.NewValue as BookmarkItem;

            CanModify = true;
        }

        private void BtnModify_OnClick(object sender, RoutedEventArgs e)
        {
            var bookmarkItem = TvBookmarks.SelectedItem as BookmarkItem;

            if (bookmarkItem.Index >= _Pdf.Bookmarks.Count)
            {
                bookmarkItem.Index = _Pdf.Bookmarks.Count - 1;
            }
            PdfBookmark bookmark = _Pdf.Bookmarks[bookmarkItem.Index];

            int pageIndex = bookmarkItem.Page - 1;
            if (pageIndex >= _Pdf.Pages.Count)
            {
                pageIndex = _Pdf.Pages.Count - 1;
            }

            bookmark.Destination = new PdfDestination(_Pdf.Pages[pageIndex]);
            bookmark.Title = bookmarkItem.Title;

            //_Pdf.SaveToFile(_FileName);
            //LoadBookmarks();
        }

        private void BtnDelete_OnClick(object sender, RoutedEventArgs e)
        {
            var bookmarkItem = TvBookmarks.SelectedItem as BookmarkItem;
        }

        private void BtnAdd_OnClick(object sender, RoutedEventArgs e)
        {
			MessageBox.Show("见 https://gitee.com/dlgcy/SpirePdfTool");
		}

        private void BtnRefresh_OnClick(object sender = null, RoutedEventArgs e = null)
        {
            if (LoadBookmarks())
            {
                MessageBox.Show("刷新成功");
            }
            else
            {
                MessageBox.Show("刷新失败");
            }
        }

        private void BtnWrite_OnClick(object sender, RoutedEventArgs e)
        {
            _Pdf.SaveToFile(_FileName);
            MessageBox.Show($"【{_FileName}】已保存");
        }

        private void Hyperlink_OnClick(object sender, RoutedEventArgs e)
        {
            try
            {
                Hyperlink link = sender as Hyperlink;
                string url = link.NavigateUri.AbsoluteUri;

                #region //.NET Framework 方式

                //var processStartInfo = new ProcessStartInfo(url);
                //Process.Start(processStartInfo);

                #endregion

                #region //.NET Core 方式

                Process process = new Process
                {
                    StartInfo =
                    {
                        FileName = "cmd.exe",
                        UseShellExecute = false,            //不使用shell启动
                        RedirectStandardInput = true,       //让cmd接受标准输入
                        RedirectStandardOutput = false,     //不想听cmd讲话所以不要他输出
                        RedirectStandardError = true,       //重定向标准错误输出
                        CreateNoWindow = true,              //不显示窗口
                    }
                };

                process.Start();

                //向cmd窗口发送输入信息 后面的&exit告诉cmd运行好之后就退出
                process.StandardInput.WriteLine($"start {url}&exit");
                process.StandardInput.AutoFlush = true;
                process.WaitForExit();//等待程序执行完退出进程
                process.Close();

                #endregion
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
    }

    public class BookmarkItem
    {
        public int Index { get; set; }
        public int Page { get; set; }
        public string Title { get; set; }
    }
}
